package cc.rboot.masking.helper;

import cc.rboot._core.helper.ClassHelper;
import cc.rboot.masking.annotation.DataMasking;
import com.baomidou.mybatisplus.core.metadata.IPage;
import cc.rboot.masking.core.IDataMaskingProcessor;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public class DataMaskingHelper {

    private static final Map<Class, List<Field>> DATA_MASKING_FIELD_LIST_MAP = new ConcurrentHashMap<>();

    public static void masking(Object data) throws InstantiationException, IllegalAccessException {
        if (data instanceof IPage) {
            IPage page = (IPage) data;
            for (Object record : page.getRecords()) {
                DataMaskingHelper.processDataMasking(record);
            }
        } else if (data instanceof List) {
            List list = (List) data;
            for (Object record : list) {
                DataMaskingHelper.processDataMasking(record);
            }
        } else {
            DataMaskingHelper.processDataMasking(data);
        }
    }


    private static void processDataMasking(Object record) throws IllegalAccessException, InstantiationException {
        if (record == null) {
            return;
        }
        for (Field maskingField : getDataMaskingFieldList(record.getClass())) {
            DataMasking dataMasking = maskingField.getDeclaredAnnotation(DataMasking.class);
            Class<? extends IDataMaskingProcessor> dataMaskingProcessor = dataMasking.processor();
            maskingField.setAccessible(true);
            Object param = maskingField.get(record);
            if (param != null) {
                Object newValue = dataMaskingProcessor.newInstance().masking(maskingField.get(record), dataMasking.condition());
                maskingField.set(record, newValue);
            }
        }
    }


    private static List<Field> getDataMaskingFieldList(Class recordClass) {
        if (DATA_MASKING_FIELD_LIST_MAP.containsKey(recordClass)) {
            return DATA_MASKING_FIELD_LIST_MAP.get(recordClass);
        }

        List<Field> fieldList = new LinkedList<>();

        for (Field declaredField : ClassHelper.getAllFieldList(recordClass)) {
            DataMasking dataMasking = declaredField.getDeclaredAnnotation(DataMasking.class);
            if (dataMasking != null) {
                fieldList.add(declaredField);
            }
        }
        DATA_MASKING_FIELD_LIST_MAP.put(recordClass, fieldList);
        return fieldList;
    }
}
